package com.wlyuan.open.scanner.repository.impl;

import com.wlyuan.open.scanner.dao.entity.PriceDocIndexDO;
import com.wlyuan.open.scanner.dao.mapper.OrderIndexMapper;
import com.wlyuan.open.scanner.dao.mapper.PriceDocIndexMapper;
import com.wlyuan.open.scanner.domain.quotation.*;
import com.wlyuan.open.scanner.repository.*;
import com.wlyuan.open.scanner.utils.StreamUtils;
import com.wlyuan.open.scanner.utils.enums.YesOrNoEnum;
import com.wlyuan.open.scanner.utils.enums.quotation.*;
import com.wlyuan.open.utils.LongUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import lombok.var;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
 * @author lijing
 * @description
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class QuotationCombineRepositoryImpl implements QuotationCombineRepository {
    private final PriceDocIndexMapper priceDocIndexMapper;
    private final QuotationDetailRepository quotationDetailRepository;
    private final OrderIndexMapper orderIndexMapper;
    private final PriceOrderCacheRepository priceOrderCacheRepository;
    private final QuotationUpDowRepository quotationUpDowRepository;
    private final OrderContainRepository orderContainRepository;
    private final BaseOrderRepository baseOrderRepository;
    private final QuotationRelationRepository quotationRelationRepository;

    @Override
    public void sync() {
    }

    @Override
    public List<CombineQuotation> list() {
        return Collections.emptyList();
    }

    @Override
    public CombineQuotation getByOrderId(Long orderId) {
        return Optional.ofNullable(orderId).map(id -> {
            var quotationRelation = quotationRelationRepository.getByWaybillId(id);
            if (quotationRelation == null) {
                logger.error("quotationRelation关系中没数据：combineId：{}", id);
                return null;
            }
            var quotation = orderIndexMapper.getQuotationOrderByOrderId(id);
            quotation.setCreateAt(quotationRelation.getQuotationAt());
            return parse(quotation);
        }).orElse(null);
    }

    @Override
    public void getByTenantId(Long tenantId) {

    }

    @Override
    public CombineQuotation parse(QuotationOrder data) {
        if (!Optional.ofNullable(data).isPresent()) {
            return null;
        }
        //总费用是否为0
        /*if (NumberUtils.compareZero(data.getTotalCost()) && NumberUtils.compareZero(NumberUtils.add(data.getFullCost(), data.getLessCost()))) {
            logger.error("运单总费用为0 并且 零担+整车费用为0,不同步报价信息");
            return null;
        }*/
        var q = CombineQuotationConvert.convert(data);
        q.setWaybills(orderContainRepository.getOrderSpecByOrderId(data.getOrderId()));
        //已审核的报价信息
        var list = priceDocIndexMapper.getCombineQuotationByOrderId(data.getOrderId());
        if (!CollectionUtils.isEmpty(list)) {
            //是否存在按单报价
            var quotationData = list.stream().filter(x -> TemplateTypeEnum.isQuote(x.getIndexType()) || TemplateTypeEnum.isCombineQuote(x.getIndexType())).findFirst().orElse(null);
            if (Optional.ofNullable(quotationData).isPresent()) {
                //手动报价(按单报价 和 补充报价)
                manual(quotationData, list, q);
            } else {
                //不存在按单报价，则为合约匹配（合约匹配 + 补充报价）
                q = match(data.getOrderId(), list, q);
            }
        } else {
            //为空，则说明不存在按单报价和补充报价，需要判断是否存在匹配合约的数据，匹配合约的在priceIndex表中orderId字段没值
            q = match(data.getOrderId(), q);
        }
        //费用明细为空
        if (CollectionUtils.isEmpty(q.getFees())) {
            logger.error("拼车单费用明细为空：{}", data.getOrderId());
            return null;
        }
        //发货方  和  承运方
        var upAndDown = quotationUpDowRepository.upAndDown(data.getOrderId(), data.getType());
        //发货方
        q.setCustomer(CombineQuotationConvert.downConvert(upAndDown));
        //承运方
        q.setCarrier(CombineQuotationConvert.upConvert(upAndDown));
        return q;
    }

    /**
     * 手动匹配报价处理
     *
     * @param priceDocIndex
     * @param data
     * @param quotation
     */
    private void manual(PriceDocIndexDO priceDocIndex, List<PriceDocIndexDO> data, CombineQuotation quotation) {
        //按单报价
        commonQuote(priceDocIndex, quotation);
        //补充报价
        var replenishQuotation = data.stream().filter(x -> (TemplateTypeEnum.isAddQuote(x.getIndexType()) || TemplateTypeEnum.isCombineAddQuote(x.getIndexType())) && QuotationStatusEnum.addQuote(x.getIndexStatus())).collect(Collectors.toList());
        replenish(replenishQuotation, quotation);
    }

    /**
     * 按单报价
     *
     * @param priceDocIndexDO
     */
    private void commonQuote(PriceDocIndexDO priceDocIndexDO, CombineQuotation quotation) {
        quotation.setRemarks(priceDocIndexDO.getIndexDescription());
        var surcharge = QuotationConvert.convert(priceDocIndexDO);
        if (TemplateTypeEnum.isCombineQuote(priceDocIndexDO.getIndexType())) {
            surcharge.setType(QuotationTypeEnum.COMMON_QUOTE.getValue());
        } else {
            surcharge.setType(QuotationTypeEnum.TEMPLATE_QUOTE.getValue());
        }
        //议价发起方
        if (QuotationStatusEnum.BARGAIN.equals(priceDocIndexDO.getIndexStatus())) {
            surcharge.setTenantId(reviewingIssuer(priceDocIndexDO.getIndexFromtype(), priceDocIndexDO.getIndexCustomercompanyid(), priceDocIndexDO.getIndexOrderid(), priceDocIndexDO.getIndexCreatorcompanyid()));
        }
        //按单报价才去拿明细，合约匹配不拿明细
        if (TemplateTypeEnum.isCombineQuote(priceDocIndexDO.getIndexType())) {
            var list = quotationDetailRepository.getDetailsFee(priceDocIndexDO.getIndexId());
            if (!CollectionUtils.isEmpty(list)) {
                //运输费 整车 + 零担 + 税费
                surcharge.setTransportFee(priceMatch(list, x -> QuotationDetailTypeEnum.FULL_LOAD.getValue().equals(x.getType()) || QuotationDetailTypeEnum.LESS_LOAD.getValue().equals(x.getType())));
                //装货费
                surcharge.setLoadFee(priceMatch(list, x -> QuotationDetailTypeEnum.ON_LOAD.getValue().equals(x.getType())));
                //卸货费
                surcharge.setUnloadFee(priceMatch(list, x -> QuotationDetailTypeEnum.OFF_LOAD.getValue().equals(x.getType())));
                //提货费
                surcharge.setPickFee(priceMatch(list, x -> QuotationDetailTypeEnum.PICK.getValue().equals(x.getType())));
                //送货费
                surcharge.setDeliverFee(priceMatch(list, x -> QuotationDetailTypeEnum.DELIVERY.getValue().equals(x.getType())));
                //保险费
                surcharge.setInsureFee(priceMatch(list, x -> QuotationDetailTypeEnum.INSURANCE.getValue().equals(x.getType())));
                //税费
                surcharge.setTaxFee(priceMatch(list, x -> QuotationDetailTypeEnum.TAX.getValue().equals(x.getType())));
                //预付款
                surcharge.setPrepayFee(priceMatch(list, x -> QuotationDetailTypeEnum.PAYMENT.getValue().equals(x.getType())));
                //到付款
                surcharge.setArrivePayFee(priceMatch(list, x -> QuotationDetailTypeEnum.PAYABLE.getValue().equals(x.getType())));
                //代收货款
                surcharge.setCollectionFee(priceMatch(list, x -> QuotationDetailTypeEnum.COLLECTION.getValue().equals(x.getType())));
                //最低费用
                surcharge.setMinimumFee(priceMatch(list, x -> QuotationDetailTypeEnum.MIN.getValue().equals(x.getType())));

                surcharge.setSurchargeFees(fees(list));
            }
            List<QuotationSurcharge> fees = new ArrayList<>();
            fees.add(surcharge);
            quotation.setFees(fees);
        }
    }

    /**
     * 合约匹配
     *
     * @param orderId
     * @param quotation
     * @return
     */
    private CombineQuotation match(Long orderId, CombineQuotation quotation) {
        var match = priceOrderCacheRepository.getNoAdditionMatchInfo(orderId);
        return Optional.ofNullable(match).map(m -> CombineQuotationConvert.convert(quotation, m)).orElse(quotation);
    }

    /**
     * 匹配到合约
     *
     * @param orderId
     * @param data
     * @param quotation
     */
    private CombineQuotation match(Long orderId, List<PriceDocIndexDO> data, CombineQuotation quotation) {
        quotation = match(orderId, quotation);
        //补充报价
        var replenishQuotation = data.stream().filter(x -> (TemplateTypeEnum.isAddQuote(x.getIndexType()) || TemplateTypeEnum.isCombineAddQuote(x.getIndexType())) && QuotationStatusEnum.addQuote(x.getIndexStatus())).collect(Collectors.toList());
        replenish(replenishQuotation, quotation);
        return quotation;
    }

    /**
     * 补充报价
     *
     * @param replenishList
     * @param quotation
     */
    private void replenish(List<PriceDocIndexDO> replenishList, CombineQuotation quotation) {
        if (!CollectionUtils.isEmpty(replenishList)) {
            //补充费用集合（审核通过的补充报价信息）
            var agrees = replenishList.stream().filter(x -> QuotationStatusEnum.AGREE.getValue().equals(x.getIndexStatus())).collect(Collectors.toList());
            if (!CollectionUtils.isEmpty(agrees)) {
                var agreeList = agrees.stream().map(agree -> {
                    var surcharge = QuotationConvert.convert(agree);
                    surcharge.setType(QuotationTypeEnum.ADD_QUOTE.getValue());
                    var list = quotationDetailRepository.getDetailsFee(agree.getIndexId());
                    //运输费 整车 + 零担 + 税费
                    surcharge.setTransportFee(priceMatch(list, x -> QuotationDetailTypeEnum.FULL_LOAD.getValue().equals(x.getType()) || QuotationDetailTypeEnum.LESS_LOAD.getValue().equals(x.getType())));
                    //装货费
                    surcharge.setLoadFee(priceMatch(list, x -> QuotationDetailTypeEnum.ON_LOAD.getValue().equals(x.getType())));
                    //卸货费
                    surcharge.setUnloadFee(priceMatch(list, x -> QuotationDetailTypeEnum.OFF_LOAD.getValue().equals(x.getType())));
                    //提货费
                    surcharge.setPickFee(priceMatch(list, x -> QuotationDetailTypeEnum.PICK.getValue().equals(x.getType())));
                    //送货费
                    surcharge.setDeliverFee(priceMatch(list, x -> QuotationDetailTypeEnum.DELIVERY.getValue().equals(x.getType())));
                    //保险费
                    surcharge.setInsureFee(priceMatch(list, x -> QuotationDetailTypeEnum.INSURANCE.getValue().equals(x.getType())));
                    //税费
                    surcharge.setTaxFee(priceMatch(list, x -> QuotationDetailTypeEnum.TAX.getValue().equals(x.getType())));
                    //预付款
                    surcharge.setPrepayFee(priceMatch(list, x -> QuotationDetailTypeEnum.PAYMENT.getValue().equals(x.getType())));
                    //到付款
                    surcharge.setArrivePayFee(priceMatch(list, x -> QuotationDetailTypeEnum.PAYABLE.getValue().equals(x.getType())));
                    //代收货款
                    surcharge.setCollectionFee(priceMatch(list, x -> QuotationDetailTypeEnum.COLLECTION.getValue().equals(x.getType())));
                    //最低费用
                    surcharge.setMinimumFee(priceMatch(list, x -> QuotationDetailTypeEnum.MIN.getValue().equals(x.getType())));

                    surcharge.setSurchargeFees(fees(list));
                    return surcharge;
                }).collect(Collectors.toList());

                if (CollectionUtils.isEmpty(quotation.getFees())) {
                    quotation.setFees(new ArrayList<>());
                }
                quotation.getFees().addAll(agreeList);
            }

            //补充报价信息（待审核 和 议价的补充报价信息,不包含草稿和被拒绝的） ，当前操作的只会又一个待处理的
            var waiteProcess = replenishList.stream().filter(x -> !QuotationStatusEnum.AGREE.getValue().equals(x.getIndexStatus())).collect(Collectors.toList());
            if (!CollectionUtils.isEmpty(waiteProcess)) {
                var waiteList = waiteProcess.stream().map(wait -> {
                    var surcharge = QuotationConvert.convert(wait);
                    surcharge.setType(QuotationTypeEnum.ADD_QUOTE.getValue());
                    //议价会有多次,双方都可以发起
                    if (TemplateTypeEnum.BARGAIN.getValue().equals(wait.getIndexStatus())) {
                        surcharge.setTenantId(reviewingIssuer(wait.getIndexFromtype(), wait.getIndexCustomercompanyid(), wait.getIndexOrderid(), wait.getIndexCreatorcompanyid()));
                    }
                    surcharge(wait, surcharge);
                    return surcharge;
                }).collect(Collectors.toList());
                if (CollectionUtils.isEmpty(quotation.getFees())) {
                    quotation.setFees(new ArrayList<>());
                }
                quotation.getFees().addAll(waiteList);
            }
        }
    }

    private Long reviewingIssuer(Integer fromType, Long customerCompanyId, Long orderId, Long createCompanyId) {
        //承运方发起，给客户
        if (YesOrNoEnum.isNo(fromType)) {
            return customerCompanyId;
        }
        //客户发起，给承运方
        if (YesOrNoEnum.isYes(fromType) && LongUtils.notNullLong(orderId)) {
            var order = orderIndexMapper.getByOrderId(orderId);
            return Optional.ofNullable(order).map(o -> {
                if (LongUtils.notNullLong(o.getIndexSuppliercompanyid())) {
                    return o.getIndexSuppliercompanyid();
                }
                //获取订单承运方信息
                baseOrderRepository.processCarrier(o);
                //承运方所属租户
                return Optional.ofNullable(o.getUpTenantId()).orElse(createCompanyId);
            }).orElse(createCompanyId);
        }
        return createCompanyId;
    }

    /**
     * 待审核费用信息
     *
     * @param data
     * @return
     */
    private void surcharge(PriceDocIndexDO data, QuotationSurcharge surcharge) {
        var list = quotationDetailRepository.getDetailsFee(data.getIndexId());
        surcharge.setSurchargeFees(fees(list));
        //运输费 整车 + 零担 + 税费
        surcharge.setTransportFee(priceMatch(list, x -> QuotationDetailTypeEnum.FULL_LOAD.getValue().equals(x.getType()) || QuotationDetailTypeEnum.LESS_LOAD.getValue().equals(x.getType())));
        //装货费
        surcharge.setLoadFee(priceMatch(list, x -> QuotationDetailTypeEnum.ON_LOAD.getValue().equals(x.getType())));
        //卸货费
        surcharge.setUnloadFee(priceMatch(list, x -> QuotationDetailTypeEnum.OFF_LOAD.getValue().equals(x.getType())));
        //提货费
        surcharge.setPickFee(priceMatch(list, x -> QuotationDetailTypeEnum.PICK.getValue().equals(x.getType())));
        //送货费
        surcharge.setDeliverFee(priceMatch(list, x -> QuotationDetailTypeEnum.DELIVERY.getValue().equals(x.getType())));
        //保险费
        surcharge.setInsureFee(priceMatch(list, x -> QuotationDetailTypeEnum.INSURANCE.getValue().equals(x.getType())));
        //税费
        surcharge.setTaxFee(priceMatch(list, x -> QuotationDetailTypeEnum.TAX.getValue().equals(x.getType())));
        //预付款
        surcharge.setPrepayFee(priceMatch(list, x -> QuotationDetailTypeEnum.PAYMENT.getValue().equals(x.getType())));
        //到付款
        surcharge.setArrivePayFee(priceMatch(list, x -> QuotationDetailTypeEnum.PAYABLE.getValue().equals(x.getType())));
        //代收货款
        surcharge.setCollectionFee(priceMatch(list, x -> QuotationDetailTypeEnum.COLLECTION.getValue().equals(x.getType())));
        //最低费用
        surcharge.setMinimumFee(priceMatch(list, x -> QuotationDetailTypeEnum.MIN.getValue().equals(x.getType())));
    }

    private List<SurchargeFee> fees(List<QuotationDetail> list) {
        if (CollectionUtils.isEmpty(list)) {
            return Collections.emptyList();
        }
        list = list.stream().filter(x -> QuotationDetailTypeEnum.ADDITION.getValue().equals(x.getType())).collect(Collectors.toList());
        list.stream().forEach(x -> {
            //报价附加费
            if (QuotationDetailTypeEnum.ADDITION.getValue().equals(x.getType()) && x.getAdditionType() == null) {
                x.setType(QuotationSurchargeTypeEnum.ADDITION_OTHER.getValue());
            }
        });
        return QuotationDetailConvert.convertSurcharge(list);

    }

    private BigDecimal bill(List<QuotationDetail> list, Predicate<QuotationDetail> predicate, BigDecimal defaultValue) {
        return Optional.ofNullable(list.stream().filter(predicate).findFirst().orElse(null))
                .map(QuotationDetail::getPrice)
                .orElse(defaultValue);
    }

    private BigDecimal priceMatch(List<QuotationDetail> list, Predicate<QuotationDetail> predicate) {
        var result = list.stream().filter(predicate).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(result)) {
            return null;
        }
        return StreamUtils.sum(result, QuotationDetail::getPrice, BigDecimal::add, BigDecimal.ZERO);
    }
}
